package knapsackProblem;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.joda.time.Instant;

import almm.GeneralizedState;
import almm.ProperState;
import almm.TimeInstant;

public final class GeneralizedStateSet {

	private static volatile Map<almm.TimeInstant, Map<almm.ProperState, GeneralizedState>> generalizedStates = null;
	private static volatile Set<GeneralizedState> notAdmissibleStates = null;
	private static volatile Set<GeneralizedState> goalStates = null;

	public static GeneralizedState getGeneralizedState(
			almm.ProperState properState, almm.TimeInstant t) throws Exception {

		if (generalizedStates == null || !generalizedStates.containsKey(t)
				|| !generalizedStates.get(t).containsKey(properState))
			throw new Exception(
					"GeneralizedStateSet.getGeneralizedState(almm.ProperState,almm.TimeInstant) method is to get existing elements");

		return GeneralizedStateSet.generalizedStates.get(t).get(properState);
	}

	public static Set<GeneralizedState> getGeneralizedStates() {
		Set<GeneralizedState> gsSetToReturn = new HashSet<GeneralizedState>();
		if (generalizedStates == null)
			return gsSetToReturn;

		for (Map<ProperState, GeneralizedState> map : ((Map<TimeInstant, Map<ProperState, GeneralizedState>>) generalizedStates)
				.values()) {
			for (GeneralizedState gs : map.values()) {
				gsSetToReturn.add(gs);
			}
		}
		return gsSetToReturn;
	}

	public static Set<GeneralizedState> getNotAdmissibleStates() {
		return (notAdmissibleStates == null) ? new HashSet<GeneralizedState>()
				: notAdmissibleStates;
	}

	public static Set<GeneralizedState> getGoalStates() {
		return (goalStates == null) ? new HashSet<GeneralizedState>()
				: goalStates;
	}

	public static boolean addGeneralizedState(almm.ProperState properState,
			almm.TimeInstant t, final Instant FINISH_TIME,
			final int howManyTasks) {
		if (generalizedStates == null || notAdmissibleStates == null
				|| goalStates == null) {
			synchronized (GeneralizedStateSet.class) {
				if (generalizedStates == null)
					generalizedStates = new HashMap<almm.TimeInstant, Map<almm.ProperState, almm.GeneralizedState>>();
				if (notAdmissibleStates == null)
					notAdmissibleStates = new HashSet<GeneralizedState>();
				if (goalStates == null)
					goalStates = new HashSet<GeneralizedState>();
			}
		}

		if (!generalizedStates.containsKey(t))
			generalizedStates.put(t,
					new HashMap<almm.ProperState, GeneralizedState>());

		if (generalizedStates.get(t).containsKey(properState))
			return false;
		else {
			GeneralizedState gs = new GeneralizedState(properState, t) {
				@Override
				public Boolean isNotAdmissibleState() {
					return super.getT().getTimeInstant().compareTo(FINISH_TIME) > 0;
				}

				@Override
				public Boolean isGoalState() {
					return (howManyTasks == super.getProperState()
							.getCurrentState().size());
				}

			};
			generalizedStates.get(t).put(properState, gs);

			if (gs.isNotAdmissibleState())
				notAdmissibleStates.add(gs);
			if (gs.isGoalState())
				goalStates.add(gs);

			return true;
		}
	}

	public static GeneralizedState getGeneralizedState(
			almm.ProperState properState, almm.TimeInstant t,
			final Instant FINISH_TIME, final int howManyTasks) throws Exception {
		addGeneralizedState(properState, t, FINISH_TIME, howManyTasks);
		return getGeneralizedState(properState, t);
	}

	private GeneralizedStateSet() {
	}
}
